#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#define SCM_BASE    (0x48002000)
#define SCM_LEN     (4*1024)
#define ControlStatus   (0x44C)

static char *SGX[4] = {
  "Full use", "Core clock restricted in HW to /6 from L3", "HW not present", "Reserved"
};
static int MHZ[4] = { 600, 400, 266, 0 };

static void show_chip(int fd)
{
    unsigned char *scm_base = (unsigned char *)mmap(NULL, SCM_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, SCM_BASE);
    unsigned short status = *(volatile unsigned short *)(scm_base + ControlStatus);
    if (scm_base == MAP_FAILED) {
        fprintf(stderr, "mmap 0x%x failed\n", SCM_BASE);
        return;
    }
    printf("Chip Indentification(0x%04x): ", status);
    switch (status) {
    case 0x0c00:
        printf("OMAP3530\n");
        break;
    case 0x4c00:
        printf("OMAP3525\n");
        break;
    case 0x1c00:
        printf("OMAP3515\n");
        break;
    case 0x5c00:
        printf("OMAP3503\n");
        break;
    default:
        printf("Unkown\n");
        break;
    }
    printf("SGX               : %s\n", SGX[(status>>13)&0x3]);
    printf("IVA               : %s\n", (status>>12)&0x1 ? "HW accelerators disabled" : "Full use");
    printf("MPU L2 cache size : Full use (256 KB)\n");
    printf("MPU Frequency     : 600 MHz\n");
    printf("IVA2 Frequency    : 430 MHz\n");
    printf("ISP               : Full use\n");
    printf("NEON & VFP        : Full use\n");
    printf("FL3G&CMADS display: Full use\n");
    printf("CCP2/CSI1 Serial Camera: Fulluse\n");
    printf("MMC1 Width        : Full use(8-bit width at 3.0v IO)\n");
    printf("TV Out            : Full use\n");

    munmap(scm_base, SCM_LEN);
}

int main(int argc, char const* argv[])
{
	int fd_mem;
	unsigned char *base;

	if ((fd_mem = open("/dev/mem", O_RDWR | O_NDELAY)) == -1) 
	{
		perror ("/dev/mem");
		return -1;
	}

	base= (unsigned char *)
		mmap (NULL,  4*1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd_mem, 0x4830a000);
    printf("Serial Number: %08x%08x%08x%08x\n", *(volatile long *)(base+0x224), *(volatile long *)(base+0x220), *(volatile long *)(base+0x21c), *(volatile long *)(base+0x218));
//	int i = 0;
//	for (i=0x227; i>=0x218; --i) {
//		printf("%02x", *(volatile char *)(base+i));
//	}

    show_chip(fd_mem);

    munmap(base, 4*1024);

    close(fd_mem);

	return 0;
}
